﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace TripLOA.WebService.Wrappers
{
    [DataContract]
    public class FullTripInfo : TripInfo
    {
        public FullTripInfo()
            : base()
        {}
        
        public FullTripInfo(Groupware.Trip t)
            : base(t)
        {
            this.Accomplished = t.Accomplished;
            this.DeviationRadius = t.DeviationRadius;
            this.Draft = t.Draft;
            this.EstimatedTime = t.EstimatedTime;
            this.RequireLicensed = t.RequireLicenced;
            this.RealBudget = t.RealBudget;
            this.RealTime = t.RealTime;
            this.ReservationExpirationDate = t.ReservationExpirationDate;
            this.Notes = t.Notes;
            this.AcceptSmoker = t.AcceptSmoker;
            this.ReservatedUsers = new List<UserInfo>();
            
            //TODO sostituire con il metodo di Groupware (ora i profili hanno l'ID)
            //List<int> uidList = Storage.StorageManager.Instance.GetUsersWithReservationRequestByTripId(this.ID);
            List<Security.Profile> profileLIst = Groupware.TripManager.GetReservatedUsers(this.ID);
            foreach (var p in profileLIst)
            {
                this.ReservatedUsers.Add(new UserInfo() { UserID = p.Id, Username = p.Username, NumericFeedbacks = UserCore.Instance.GetUserNumericFeedback(p) });         
            }

            //Fill stages
            Stages = new List<StageInfo>();
            foreach (var stage in t.Stages())
            {
                StageInfo si = new StageInfo();
                si.BusySeats = stage.BusySeats;
                si.Distance = stage.Distance;
                si.EstimatedBudget = stage.EstimatedBudget;
                si.EstimatedTime = stage.EstimatedTime;

                si.Origin = new PlaceInfo();

                si.Origin.Address = ((stage.Origin.Address != null) ? stage.Origin.Address : "") + ", ";
                si.Origin.Address += ((stage.Origin.City != null) ? stage.Origin.City + ", " : "") + ", ";
                si.Origin.Address += ((stage.Origin.Province != null) ? stage.Origin.Province + ", " : "") + ", ";
                si.Origin.Address += (stage.Origin.State != null) ? stage.Origin.State : "";

                si.Destination = new PlaceInfo();

                si.Destination.Address = ((stage.Destination.Address != null) ? stage.Destination.Address + ", " : "") + ", ";
                si.Destination.Address += ((stage.Destination.City != null) ? stage.Destination.City + ", " : "") + ", ";
                si.Destination.Address += ((stage.Destination.Province != null) ? stage.Destination.Province + ", " : "") + ", ";
                si.Destination.Address += (stage.Destination.State != null) ? stage.Destination.State : "";

                si.Vehicle = new VehicleInfo(stage.Vehicle);
            

                Stages.Add(si);
            }
        }

        #region Properties

        [DataMember]
        public bool Accomplished { get; set; }

        [DataMember]
        public float? DeviationRadius { get; set; }

        [DataMember]
        public bool Draft { get; set; }

        [DataMember]
        public short? EstimatedTime { get; set; }

        [DataMember]
        public bool? RequireLicensed { get; set; }

        [DataMember]
        public decimal? RealBudget { get; set; }

        [DataMember]
        public short? RealTime { get; set; }

        [DataMember]
        public DateTime? ReservationExpirationDate { get; set; }

        //Note per il momento resta una stringa
        [DataMember]
        public string Notes { get; set; }

        [DataMember]
        public bool? AcceptSmoker { get; set; }

        [DataMember]
        public byte? FreeSeats { get; set; }

        [DataMember]
        public bool? IsFrequent { get; set; }

        [DataMember]
        public List<UserInfo> ReservatedUsers { get; set; }

        [DataMember]
        public bool IsBooked { get; set; }

        [DataMember]
        public bool IsInFavorites { get; set; }

        [DataMember]
        public bool IsOffered { get; set; }

        [DataMember]
        public List<StageInfo> Stages { get; set; }

        #endregion

        #region Methods

        public Groupware.Trip generateTrip()
        {
            Groupware.Trip t = null;

            //Owner
            if (this.Owner == null)
            {
                Security.Profile ownerProfile = UserCore.Instance.GetLoggedUser().GetProfile();
                this.Owner = new UserInfo() { UserID = ownerProfile.Id, Username = ownerProfile.Username };
            }

            //Stages & GeoTrip
            GeoRef.GeoQuery gq = new GeoRef.GeoQuery();

            StageInfo fs = Stages.First();
            Stages.RemoveAt(0);

            ///[Changed by Andrea Russino (same patch of TripCore, row 535)].
            ///
            ///This is only a temporary patch, in fact if the client culture provide a ',' as decimal separator
            ///the splits of lines 149, 155, 170 and 176 produce 4 lengthed arrays, due to the ambiguous usage of char ','
            ///To be robust to this situation a different char shoud be used between lat e long tokens.
            string[] originCoords = fs.Origin.Coords.Split(',');
            GeoRef.GeoLoc originLoc = gq.reverseGeoCoding(
                double.Parse(originCoords[0], System.Globalization.CultureInfo.InvariantCulture), //double.Parse(originCoords[0].Replace('.', ',')),
                double.Parse(originCoords[1], System.Globalization.CultureInfo.InvariantCulture) //double.Parse(originCoords[1].Replace('.', ','))
            );

            string[] destinationCoords = fs.Destination.Coords.Split(',');
            GeoRef.GeoLoc destinationLoc = gq.reverseGeoCoding(
                double.Parse(destinationCoords[0], System.Globalization.CultureInfo.InvariantCulture), //double.Parse(destinationCoords[0].Replace('.', ',')),
                double.Parse(destinationCoords[1], System.Globalization.CultureInfo.InvariantCulture) //double.Parse(destinationCoords[1].Replace('.', ','))
            );

            GeoRef.GeoTrip gt = new GeoRef.GeoTrip(originLoc, destinationLoc);

            gt[0].Vehicle = (GeoRef.VehicleType)fs.Vehicle.VehicleClass;
            gt[0].VehicleId = fs.Vehicle.Id;

            foreach (StageInfo s in Stages)
            {
                //if (s == fs) continue;

                originCoords = s.Origin.Coords.Split(',');
                originLoc = gq.reverseGeoCoding(
                    double.Parse(originCoords[0], System.Globalization.CultureInfo.InvariantCulture), //double.Parse(originCoords[0].Replace('.', ',')),
                    double.Parse(originCoords[1], System.Globalization.CultureInfo.InvariantCulture) //double.Parse(originCoords[1].Replace('.', ','))
                );

                destinationCoords = s.Destination.Coords.Split(',');
                destinationLoc = gq.reverseGeoCoding(
                    double.Parse(destinationCoords[0], System.Globalization.CultureInfo.InvariantCulture), //double.Parse(destinationCoords[0].Replace('.', ',')),
                    double.Parse(destinationCoords[1], System.Globalization.CultureInfo.InvariantCulture) //double.Parse(destinationCoords[1].Replace('.', ','))
                );

                GeoRef.GeoRoute gr = new GeoRef.GeoRoute(originLoc, destinationLoc);

                gr.Vehicle = (GeoRef.VehicleType)s.Vehicle.VehicleClass;
                gr.VehicleId = s.Vehicle.Id;

                gt.AddRoute(gr);
            }

            gt.UpdatePath();
            
            if (this.ID >= 0)
            {
                //Generate a Trip that already exists
                t = Groupware.TripManager.GetTripById(this.ID);
            }
            else
            {
                //Generate a new Trip
                t = new Groupware.Trip(this.Owner.UserID, gt);
            }
            
            t.AcceptSmoker = this.AcceptSmoker;
            t.Accomplished = this.Accomplished;
            t.DepartureDate = this.DepartureDate;
            t.DeviationRadius = this.DeviationRadius;
            t.Draft = this.Draft;
            t.EstimatedBudget = this.EstimatedBudget;
            t.EstimatedTime = this.EstimatedTime;
            t.FreeSeats = this.FreeSeats;
            t.Notes = this.Notes;
            t.RealBudget = this.RealBudget;
            t.RealTime = this.RealTime;
            t.IsFrequent = this.IsFrequent;
            t.RequireLicenced = this.RequireLicensed;

            //Reservation Expiration
            if (this.ReservationExpirationDate == null || !this.ReservationExpirationDate.HasValue)
            {
                //Calc Reservation Expiration Date
                //FIXME Fissate la scadenza per le prenotazioni in 3 giorni, verificare!
                this.ReservationExpirationDate = this.DepartureDate - new TimeSpan(3, 0, 0, 0);
            }
            t.ReservationExpirationDate = this.ReservationExpirationDate;

            return t;
        }

        #endregion
    }

    [DataContract]
    public class StageInfo
    {
        public StageInfo()
            :base() {}
        public StageInfo(Groupware.Stage stage)
        {
            this.BusySeats = stage.BusySeats;
            PlaceInfo destination = new PlaceInfo();
            destination.Address = ((stage.Destination.Address != null) ? stage.Destination.Address + ", " : "") + ", ";
            destination.Address += ((stage.Destination.City != null) ? stage.Destination.City + ", " : "") + ", ";
            destination.Address += ((stage.Destination.Province != null) ? stage.Destination.Province + ", " : "") + ", ";
            destination.Address += (stage.Destination.State != null) ? stage.Destination.State : "";
            this.Destination = destination;
            this.Distance = stage.Distance;
            this.EstimatedBudget = stage.EstimatedBudget;
            this.EstimatedTime = stage.EstimatedTime;
            PlaceInfo origin = new PlaceInfo();
            origin.Address = ((stage.Origin.Address != null) ? stage.Origin.Address : "") + ", ";
            origin.Address += ((stage.Origin.City != null) ? stage.Origin.City + ", " : "") + ", ";
            origin.Address += ((stage.Origin.Province != null) ? stage.Origin.Province + ", " : "") + ", ";
            origin.Address += (stage.Origin.State != null) ? stage.Origin.State : "";
            this.Origin = origin;
        }
        [DataMember]
        public PlaceInfo Origin { get; set; }

        [DataMember]
        public PlaceInfo Destination { get; set; }

        [DataMember]
        public int? BusySeats { get; set; }

        [DataMember]
        public double Distance { get; set; }

        [DataMember]
        public decimal? EstimatedBudget { get; set; }

        [DataMember]
        public short? EstimatedTime { get; set; }

        [DataMember]
        public VehicleInfo Vehicle { get; set; }
    }

    [DataContract]
    public class PlaceInfo
    {
        [DataMember]
        public string Address { get; set; }

        [DataMember]
        public string Coords { get; set; }
    }
}
